﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using RPGOnline.Controls.Chat.Events;
using RPGOnline.Remoting.Entities;
using RPGOnline.Remoting.Events;
using WeifenLuo.WinFormsUI.Docking;

namespace RPGOnline.Controls.Chat
{
    public partial class ChatControl : DockContent
    {
        private ChatControlPresenter m_presenter;
        private ChatLogger m_chatLogger;

        public ChatControl()
        {
            InitializeComponent();
        }

        public void AppendMessage(User user, ChatGroup chatGroup, string message)
        {
            if (IsDisposed) return;

            if (!string.IsNullOrEmpty(rtbChat.Text))
                rtbChat.AppendText("\r\n");

            string userFormat = string.Format("[{0}{1}]: ", 
                string.IsNullOrEmpty(user.CharacterName) ? user.Name : user.CharacterName, 
                chatGroup == null || chatGroup.Id == Guid.Empty ? "" : "@" + chatGroup.Name);

            int oldSelectionStart = rtbChat.SelectionStart;
            int oldSelectionLength = rtbChat.SelectionLength;

            rtbChat.SelectionStart = rtbChat.TextLength;
            rtbChat.SelectionLength = 0;

            rtbChat.SelectionFont = new Font(user.Font, FontStyle.Bold);
            rtbChat.SelectionColor = user.FontColor;
            rtbChat.AppendText(userFormat);

            rtbChat.SelectionFont = user.Font;
            rtbChat.AppendText(message);

            rtbChat.SelectionStart = oldSelectionStart;
            rtbChat.SelectionLength = oldSelectionLength;

            rtbChat.ScrollToCaret();

            m_chatLogger.Log(userFormat + message);
        }

        public void AppendPrivateMessage(User senderUser, User destinationUser, string message)
        {
            if (IsDisposed) return;

            if (!string.IsNullOrEmpty(rtbChat.Text))
                rtbChat.AppendText("\r\n");

            string userFormat = string.Format("[{0}>{1}]: ", 
                string.IsNullOrEmpty(senderUser.CharacterName) ? senderUser.Name : senderUser.CharacterName, 
                string.IsNullOrEmpty(destinationUser.CharacterName) ? destinationUser.Name : destinationUser.CharacterName);

            int oldSelectionStart = rtbChat.SelectionStart;
            int oldSelectionLength = rtbChat.SelectionLength;

            rtbChat.SelectionStart = rtbChat.TextLength;
            rtbChat.SelectionLength = 0;

            rtbChat.SelectionFont = new Font(senderUser.Font, FontStyle.Bold | FontStyle.Italic);
            rtbChat.SelectionColor = senderUser.FontColor;
            rtbChat.AppendText(userFormat);

            rtbChat.SelectionFont = senderUser.Font;
            rtbChat.AppendText(message);

            rtbChat.SelectionStart = oldSelectionStart;
            rtbChat.SelectionLength = oldSelectionLength;

            rtbChat.ScrollToCaret();

            m_chatLogger.Log(userFormat + message);
        }

        private void tbMessage_KeyDown(object sender, KeyEventArgs e)
        {
            string message = tbMessage.Text.Trim();
            if ((e.KeyCode == Keys.Enter || e.KeyCode == Keys.Return) && (message.Length != 0))
            {
                m_presenter.SendMessage(message);
                
                tbMessage.Text = "";
                e.Handled = true;
            }
        }

        private void tsbd4_Click(object sender, EventArgs e)
        {
            m_presenter.Roll(1,4,0);
        }

        private void tsbd6_Click(object sender, EventArgs e)
        {
            m_presenter.Roll(1, 6, 0);
        }

        private void tsbd8_Click(object sender, EventArgs e)
        {
            m_presenter.Roll(1, 8, 0);
        }

        private void tsbd10_Click(object sender, EventArgs e)
        {
            m_presenter.Roll(1, 10, 0);
        }

        private void tsbd12_Click(object sender, EventArgs e)
        {
            m_presenter.Roll(1, 12, 0);
        }

        private void tsbd20_Click(object sender, EventArgs e)
        {
            m_presenter.Roll(1, 20, 0);
        }

        private void tsbd100_Click(object sender, EventArgs e)
        {
            m_presenter.Roll(1, 100, 0);
        }

        public void UpdateUserInfo(User userToUpdate)
        {
            if (IsDisposed) return;

            TreeNode[] node = tvUsers.Nodes.Find(userToUpdate.Id.ToString(), true);
            foreach(TreeNode userNode in node)
            {
                userNode.Tag = userToUpdate;
            }
            tvUsers.Invalidate();
        }

        private void toolStripColorPicker1_SelectedColorChanged(object sender, EventArgs e)
        {
            m_presenter.UserColorChanged(toolStripColorPicker1.Color);
        }

        public void SetUserColor(Color fontColor)
        {
            if (IsDisposed) return;
            toolStripColorPicker1.Color = fontColor;
        }

        public void SetPresenter(ChatControlPresenter presenter)
        {
            m_presenter = presenter;
        }

        public void AddUser(User user)
        {
            if (IsDisposed) return;

            TreeNode treeNode = new TreeNode(user.Name);
            treeNode.Tag = user;
            treeNode.Name = user.Id.ToString();

            tvUsers.Nodes[0].Nodes.Add(treeNode);
            tvUsers.ExpandAll();
        }

        public void RemoveUser(User user)
        {
            if (IsDisposed) return;

            TreeNode[] treeNodes = tvUsers.Nodes.Find(user.Id.ToString(), true);
            foreach (var treeNode in treeNodes)
            {
                treeNode.Remove();
            }
            tvUsers.ExpandAll();
        }

        private void tvUsers_DrawNode(object sender, DrawTreeNodeEventArgs e)
        {
            var user = e.Node.Tag as User;
            if (user == null)
            {
                e.DrawDefault = true;
                return;
            }

            StringFormat stringFormat = new StringFormat();
            stringFormat.Alignment = StringAlignment.Near;
            stringFormat.LineAlignment = StringAlignment.Near;
            stringFormat.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.NoClip | StringFormatFlags.FitBlackBox;

            e.Graphics.DrawString(e.Node.Text, user.Font, new SolidBrush(user.FontColor), e.Bounds, stringFormat);
        }

        public void Update(SessionContext sessionContext)
        {
            if (IsDisposed) return;

            tvUsers.BeginUpdate();
            tvUsers.Nodes.Clear();

            foreach (ChatGroup chatGroup in sessionContext.Groups)
            {
                TreeNode chatGroupNode = tvUsers.Nodes.Add(chatGroup.Id.ToString(), "#" + chatGroup.Name);
                chatGroupNode.Tag = chatGroup;
                chatGroupNode.ContextMenuStrip = cmsGroup;

                if (m_presenter.IsDefaultChatMessageTarget(chatGroup))
                    chatGroupNode.Text += " (*)";

                FillGroup(chatGroupNode, chatGroup);
            }

            tvUsers.ExpandAll();
            tvUsers.EndUpdate();
        }

        private void FillGroup(TreeNode chatGroupNode, ChatGroup chatGroup)
        {
            foreach (User user in chatGroup.Users.Values)
            {
                string nodeText = string.IsNullOrEmpty(user.CharacterName)
                                      ? "@" + user.Name
                                      : "@" + user.CharacterName + " [" + user.Name + "]";

                TreeNode treeNode = chatGroupNode.Nodes.Add(user.Id.ToString(), nodeText);
                treeNode.Tag = user;
                treeNode.ContextMenuStrip = cmsUser;

                if (m_presenter.IsDefaultPrivateMessageTarget(user))
                    treeNode.Text += " (*)";
            }
        }

        private void tsbCreateGroup_Click(object sender, EventArgs e)
        {
            m_presenter.CreateGroup();
        }

        private void contextMenuStrip1_Opening(object sender, CancelEventArgs ce)
        {
            User user = tvUsers.SelectedNode.Tag as User;
            if(user == null)
            {
                ce.Cancel = true;
                return;
            }

            miPrivateMessageDefault.Enabled = !m_presenter.IsCurrentUser(user);
            miPrivateMessageDefault.Checked = m_presenter.IsDefaultPrivateMessageTarget(user);
            ChatGroup[] chatGroups = m_presenter.GetMoveToGroupsForUser(user);

            miMoveTo.DropDownItems.Clear();
            foreach (ChatGroup chatGroup in chatGroups)
            {
                ToolStripMenuItem menuItem = new ToolStripMenuItem(chatGroup.Name);
                ChatGroup @group = chatGroup;
                menuItem.Click += (s, e) => m_presenter.MoveUserToGroup(user, group);
                miMoveTo.DropDownItems.Add(menuItem);
            }
        }

        private void tvUsers_MouseDown(object sender, MouseEventArgs e)
        {
            if(e.Button == MouseButtons.Right)
            {
                tvUsers.SelectedNode = tvUsers.GetNodeAt(e.Location);
            }
        }

        private void setAsDefaultChatGroupToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ChatGroup chatGroup = tvUsers.SelectedNode.Tag as ChatGroup;
            if (chatGroup == null)
                return;

            m_presenter.SetDefaultChatGroupTarget(chatGroup);
        }

        private void cmsGroup_Opening(object sender, CancelEventArgs e)
        {
            ChatGroup chatGroup = tvUsers.SelectedNode.Tag as ChatGroup;
            miChatMessageDefault.Checked = m_presenter.IsDefaultChatMessageTarget(chatGroup);
            miChatMessageDefault.Enabled = m_presenter.IsMaster || chatGroup.Id == Guid.Empty ||
                                           m_presenter.IsCurrentUserInGroup(chatGroup);
        }

        private void miPrivateMessageDefault_Click(object sender, EventArgs e)
        {
            User user = tvUsers.SelectedNode.Tag as User;
            m_presenter.SetDefaultPrivateMessageTarget(user);
        }

        private void ChatControl_Load(object sender, EventArgs e)
        {
            if (DesignMode)
                return;

            m_chatLogger = new ChatLogger();

            tsbCreateGroup.Enabled = m_presenter.IsMaster;
            miMoveTo.Enabled = m_presenter.IsMaster;
        }
    }
}
